package 基础语法;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import javax.print.DocFlavor.STRING;

public class 方法引用 {
    public static void main(String[] args) {
        Integer[] a = new Integer[] { 3, 4, 1, 3, 9 };

        Arrays.sort(a, new Comparator() {// 简化为匿名内部类。这是一个函数式接口
            @Override
            public int compare(Object o1, Object o2) {
                return 1;
            }
        });

        Arrays.sort(a, (o1, o2) -> {// 简化为Lambda表达式
            return o1 - o2;
        });

        // 1.应用处必须是函数式接口
        // 2.被引用的方法必须存在
        // 3.被引用的方法必须和抽象方法的形参和返回值一致
        // 4.被引用的方法功能必须满足要求
        Arrays.sort(a, 方法引用::sort);// 简化为方法引用，直接使用已经存在的方法作为参数。这是引用静态方法的写法
        Arrays.stream(a).forEach(item -> {
            System.out.println(item);
        });
        test1();
        new TestClass().testMethodRef();
    }

    static void test1() {
        /**
         * paresInt定义为：
         * public static int parseInt(String s) throws NumberFormatException {
         * return parseInt(s,10);
         * }
         * 函数式接口定义为：
         * 
         * @FunctionalInterface
         *                      public interface Function<T, R> {
         *                      R apply(T t);
         *                      R apply(T t)与int parseInt(String s)是符合使用方法引用的条件的
         * 
         *                      }
         * 
         */
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "1", "2", "2", "2");
        List<Integer> li = arrayList.stream().map(Integer::parseInt)// 将静态方法作为方法应用
                .collect(Collectors.toList());
        System.out.println(li);
    }

    static int sort(int o1, int o2) {
        return o1 - o2;

    }

}

class TestClass {

    void testMethodRef() {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "k1", "k2", "k3", "k4", "k5", "k5");
        arrayList.stream().filter(this::filter).forEach(item -> {
            System.out.print(item + "_");
        });// 引用本类的方法
        System.out.println();
        arrayList.stream().filter(TestClass::filterStatic).forEach(item -> {
            System.out.print(item + "_");
        });// 引用静态的方法

        System.out.println();
        arrayList.stream().filter(new TestClass2()::filter).forEach(item -> {
            System.out.print(item + "_");
        });// 引用其他类的方法

        System.out.println();
        arrayList.stream().map(DemoClass::new).forEach(item -> {
            System.out.print(item + "_");
        });// 引用其他类的构造方法，要求构造方法需要提供一个与函数接口的抽象方法对应的形参列表的构造方法

    }

    void testMethodRef1() {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "k1", "k2", "k3", "k4", "k5", "k5");
        arrayList.stream().map(String::toUpperCase).forEach(item -> {
            System.out.print(item + "_");
        });// 使用类名::成员方法
        /**
         * toUpperCase：没有形参，且不是静态方法，返回值是String
         * public String toUpperCase() {
         * return toUpperCase(Locale.getDefault());
         * }
         * map函数接受的参数类型：
         * @FunctionalInterface
         * public interface Function<T, R> {
         * R apply(T t);}
         *  R apply(T t)需要接受一个参数，这显然与toUpperCase不匹配：
         * 该方式独有的规则:
         * 1.需要有函数式接口
         * 2.被引用的方法必须已经存在
         * 3.被引用方法（本例toUpperCase()）的形参，需要跟 抽象方法（本例apply(T t)）的第二形参到最后一个形参保持一致
         * 4.被引用方法的返回值需要与抽象方法的返回值保持一致
         * 5.被引用方法的功能需要满足当前需求
         * 
         * 抽象方法形参详解：
         * 第一个参数：表述被引用方法的调用者，决定了可以引用哪些类中方法
         *      在Stream流中：第一个形参一般都表示流里面的每一个数据
         *      假设流里面的数据都是字符串，那么使用这种方法进行方法引用，只能引用String这个类中的方法
         * 第二个参数到最后一个参数，跟被引用方法的形参保持一致，如果没有第二个参数，说明被引用的方法需要时无参的成员方法
         */
        testDemoInterface_DemoClass(DemoClass::demoClassInterfaceMethod);//返回值一致，第一个 参数就是DemoClass，后两个参数保持一致

    }
    
    void testMethodRef2(){
        ArrayList<Integer> arrayList=new ArrayList<>();
        Collections.addAll(arrayList, 1,2,3,4,5);
        Integer[] integers=arrayList.stream().toArray(Integer[]::new);//引用数组的构造方法,
        //
        //    <A> A[] toArray(IntFunction<A[]> generator);->    R apply(int value);
    }
    void testDemoInterface_DemoClass(DemoInterface demoInterface){//一个可以使用匿名内部类-》lambda表达式-》方法引用的参数
        demoInterface.demoInterfaceRef(null, 0, "0");//第一个参数并不使用，只是用于说明“类型”？

    }

    boolean filter(String s) {
        if (s.equals("k1")) {
            return false;
        }
        return true;
    }

    static boolean filterStatic(String s) {

        if (s.equals("k1")) {
            return false;
        }
        return true;
    }

}

class TestClass1 extends TestClass {
    void testMethodRef() {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "k1", "k2", "k3", "k4", "k5", "k5");
        arrayList.stream().filter(super::filter).forEach(item -> {
            System.out.print(item + "_");
        });// 引用父类的方法
    }

    boolean filter(String s) {
        if (s.equals("k1")) {
            return false;
        }
        return true;
    }
}

class TestClass2 {
    boolean filter(String s) {
        if (s.equals("k1")) {
            return false;
        }
        return true;
    }

}

class DemoClass {
    char k;
    char v;

    DemoClass(String s) {
        k = s.charAt(0);
        v = s.charAt(1);

    }

    @Override
    public String toString() {
        return "{K:" + "k" + ", v:" + v + "}";
    }

    String demoClassInterfaceMethod(int a,String b){
        return a+"_"+b;
    }
    

}
interface DemoInterface{//定义一个函数式接口
    String demoInterfaceRef(DemoClass demoClass,int a,String b);
}